//////////////////////////////////////
// Fast Container Library           //
// MIT License - Copyright (c) 2012 //
//////////////////////////////////////

#pragma once

#include "common.h"
#include "algobase.h"
#include "iterator.h"

FC_NAMESPACE_BEGIN


template <class T, size_t Y, size_t X>
struct static_array2d
{
	typedef size_t							size_type;
	typedef T								value_type;
	typedef value_type*						pointer;
	typedef const value_type*				const_pointer;
	typedef value_type&						reference;
	typedef const value_type&				const_reference;
	typedef pointer							iterator;
	typedef const_pointer					const_iterator;
	typedef fc::reverse_iterator<iterator> reverse_iterator;
	typedef fc::reverse_iterator<const_iterator> const_reverse_iterator;
	typedef ptrdiff_t						difference_type;
	typedef static_array2d<T, Y, X>			this_type;

	enum : size_type
	{
		array_size = X * Y,
		array_size_n_bytes = array_size * sizeof(T)
	};

	//aggregate type

	size_t size() const { return array_size; }

	iterator begin()					{ return &m_data[0]; }
	const_iterator begin() const		{ return &m_data[0]; }
	iterator end()						{ return begin() + array_size; }
	const_iterator end() const			{ return begin() + array_size; }
	reverse_iterator rend()				{ return reverse_iterator(begin()); }
	const_reverse_iterator rend() const	{ return const_reverse_iterator(begin()); }
	reverse_iterator rbegin()			{ return reverse_iterator(end()); }
	const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); }

	pointer data()					{ return &m_data[0]; }
	const_pointer data() const		{ return &m_data[0]; }
	reference front()				{ return m_data[0]; }
	const_reference front() const	{ return m_data[0]; }
	reference back()				{ return m_data[array_size - 1]; }
	const_reference back() const	{ return m_data[array_size - 1]; }

	reference		operator ()( size_t y, size_t x )			{ return m_data[ offset(y, x) ]; }
	const_reference operator ()( size_t y, size_t x ) const	{ return m_data[ offset(y, x) ]; }

	reference at( size_t y, size_t x )
	{
		FC_ASSERT(y < Y && x < X);
		return m_data[ offset(y, x) ];
	}

	const_reference at( size_t y, size_t x ) const
	{
		FC_ASSERT(y < Y && x < X);
		return m_data[ offset(y, x) ];
	}

	iterator		iterator_at( size_t y, size_t x )			{ return m_data + offset(y, x); }
	const_iterator	iterator_at( size_t y, size_t x ) const	{ return m_data + offset(y, x); }

	FC_FORCE_INLINE size_t offset( size_t y, size_t x ) const { return (x + y * X); }

	size_t x() const { return X; }
	size_t y() const { return Y; }

	void assign( const value_type& value )
	{
		fc::fill_n( begin(), size(), value );
	}

	bool iterator_is_valid( const_iterator it ) const
	{
		return (it >= begin() && it <= end());
	}

	T m_data[ array_size ]; //does not support zero sized arrays
};


template <class T, size_t Y, size_t X> inline
	bool operator ==( const static_array2d<T, Y, X>& a, const static_array2d<T, Y, X>& b )
	{
		return( &a == &b || fc::equal(a.begin(), a.end(), b.begin()) );
	}

template <class T, size_t Y, size_t X> inline
	bool operator !=( const static_array2d<T, Y, X>& a, const static_array2d<T, Y, X>& b )
	{
		return !(a == b);
	}


FC_NAMESPACE_END
